package cc.linker.steplink.crm.entity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.BitSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CookieSetUtil {
    private static final Log logger = LogFactory.getLog(DefaultCookieSerializer.class);
    private static final BitSet domainValid = new BitSet(128);
    private static String cookieName = "SESSION";
    private static Boolean useSecureCookie;
    private static boolean useHttpOnlyCookie = true;
    private static String cookiePath;
    private static Integer cookieMaxAge;
    private static String domainName;
    private static Pattern domainNamePattern;
    private static String jvmRoute;
    private static boolean useBase64Encoding = true;
    private static String rememberMeRequestAttribute;
    private static String sameSite = null;



    public static List<String> readCookieValues(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        List<String> matchingCookieValues = new ArrayList();
        if (cookies != null) {
            Cookie[] var4 = cookies;
            int var5 = cookies.length;

            for (int var6 = 0; var6 < var5; ++var6) {
                Cookie cookie = var4[var6];
                if (cookieName.equals(cookie.getName())) {
                    String sessionId = useBase64Encoding ? base64Decode(cookie.getValue()) : cookie.getValue();
                    if (sessionId != null) {
                        if (jvmRoute != null && sessionId.endsWith(jvmRoute)) {
                            sessionId = sessionId.substring(0, sessionId.length() - jvmRoute.length());
                        }

                        matchingCookieValues.add(sessionId);
                    }
                }
            }
        }

        return matchingCookieValues;
    }


    public static void writeCookieValue(CookieSerializer.CookieValue cookieValue) {
        HttpServletRequest request = cookieValue.getRequest();
        boolean wxBrowser = isWxBrowser(request);
        HttpServletResponse response = cookieValue.getResponse();
        StringBuilder sb = new StringBuilder();
        sb.append(cookieName).append('=');
        String value = getValue(cookieValue);
        if (value != null && value.length() > 0) {
            validateValue(value);
            sb.append(value);
        }

        int maxAge = getMaxAge(cookieValue);
        if (maxAge > -1) {
            sb.append("; Max-Age=").append(cookieValue.getCookieMaxAge());
            OffsetDateTime expires = maxAge != 0 ? OffsetDateTime.now().plusSeconds((long) maxAge) : Instant.EPOCH.atOffset(ZoneOffset.UTC);
            sb.append("; Expires=").append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
        }

        String domain = getDomainName(request);
        if (domain != null && domain.length() > 0) {
            validateDomain(domain);
            sb.append("; Domain=").append(domain);
        }

        String path = getCookiePath(request);
        if (path != null && path.length() > 0) {
            validatePath(path);
            sb.append("; Path=").append(path);
        }

        if (isSecureCookie(request) && !wxBrowser) {
            sb.append("; Secure");
        }

        if (useHttpOnlyCookie) {
            sb.append("; HttpOnly");
        }

        if (sameSite != null && !wxBrowser) {
            sb.append("; SameSite=").append(sameSite);
        }

        response.addHeader("Set-Cookie", sb.toString());
    }

    private static boolean isWxBrowser(HttpServletRequest request) {
        String header = request.getHeader("User-Agent");
        if (header == null) {
            return false;
        }
        header = header.toLowerCase();
        return !StringUtils.isEmpty(header) && header.contains("micromessenger");
    }

    private static String base64Decode(String base64Value) {
        try {
            byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);
            return new String(decodedCookieBytes);
        } catch (Exception var3) {
            logger.debug("Unable to Base64 decode value: " + base64Value);
            return null;
        }
    }

    private static String base64Encode(String value) {
        byte[] encodedCookieBytes = Base64.getEncoder().encode(value.getBytes());
        return new String(encodedCookieBytes);
    }

    private static String getValue(CookieSerializer.CookieValue cookieValue) {
        String requestedCookieValue = cookieValue.getCookieValue();
        String actualCookieValue = requestedCookieValue;
        if (jvmRoute != null) {
            actualCookieValue = requestedCookieValue + jvmRoute;
        }

        if (useBase64Encoding) {
            actualCookieValue = base64Encode(actualCookieValue);
        }

        return actualCookieValue;
    }

    private static void validateValue(String value) {
        int start = 0;
        int end = value.length();
        if (end > 1 && value.charAt(0) == '"' && value.charAt(end - 1) == '"') {
            start = 1;
            --end;
        }

        char[] chars = value.toCharArray();

        for (int i = start; i < end; ++i) {
            char c = chars[i];
            if (c < '!' || c == '"' || c == ',' || c == ';' || c == '\\' || c == 127) {
                throw new IllegalArgumentException("Invalid character in cookie value: " + Integer.toString(c));
            }
        }

    }

    private static int getMaxAge(CookieSerializer.CookieValue cookieValue) {
        int maxAge = cookieValue.getCookieMaxAge();
        if (maxAge < 0) {
            if (rememberMeRequestAttribute != null && cookieValue.getRequest().getAttribute(rememberMeRequestAttribute) != null) {
                cookieValue.setCookieMaxAge(2147483647);
            } else if (cookieMaxAge != null) {
                cookieValue.setCookieMaxAge(cookieMaxAge);
            }
        }

        return cookieValue.getCookieMaxAge();
    }

    private static void validateDomain(String domain) {
        int i = 0;
        int cur = -1;

        for (char[] chars = domain.toCharArray(); i < chars.length; ++i) {
            int prev = cur;
            cur = chars[i];
            if (!domainValid.get(cur) || (prev == 46 || prev == -1) && (cur == 46 || cur == 45) || prev == 45 && cur == 46) {
                throw new IllegalArgumentException("Invalid cookie domain: " + domain);
            }
        }

        if (cur == 46 || cur == 45) {
            throw new IllegalArgumentException("Invalid cookie domain: " + domain);
        }
    }

    private static void validatePath(String path) {
        char[] var2 = path.toCharArray();
        int var3 = var2.length;

        for (int var4 = 0; var4 < var3; ++var4) {
            char ch = var2[var4];
            if (ch < ' ' || ch > '~' || ch == ';') {
                throw new IllegalArgumentException("Invalid cookie path: " + path);
            }
        }

    }

    public static void setUseSecureCookie(boolean useSecureCookie) {
        useSecureCookie = useSecureCookie;
    }

    public static void setUseHttpOnlyCookie(boolean useHttpOnlyCookie) {
        useHttpOnlyCookie = useHttpOnlyCookie;
    }

    private static boolean isSecureCookie(HttpServletRequest request) {
        return useSecureCookie == null ? request.isSecure() : useSecureCookie;
    }

    public static void setCookiePath(String cookiePath) {
        cookiePath = cookiePath;
    }

    public static void setCookieName(String cookieName) {
        if (cookieName == null) {
            throw new IllegalArgumentException("cookieName cannot be null");
        } else {
            cookieName = cookieName;
        }
    }

    public static void setCookieMaxAge(int cookieMaxAge) {
        cookieMaxAge = cookieMaxAge;
    }

    public static void setDomainName(String domainName) {
        if (domainNamePattern != null) {
            throw new IllegalStateException("Cannot set both domainName and domainNamePattern");
        } else {
            domainName = domainName;
        }
    }


    public static void setJvmRoute(String jvmRoute) {
        jvmRoute = "." + jvmRoute;
    }

    public static void setUseBase64Encoding(boolean useBase64Encoding) {
        useBase64Encoding = useBase64Encoding;
    }

    public static void setRememberMeRequestAttribute(String rememberMeRequestAttribute) {
        if (rememberMeRequestAttribute == null) {
            throw new IllegalArgumentException("rememberMeRequestAttribute cannot be null");
        } else {
            rememberMeRequestAttribute = rememberMeRequestAttribute;
        }
    }

    public static void setSameSite(String sameSite) {
        sameSite = sameSite;
    }

    private static String getDomainName(HttpServletRequest request) {
        if (domainName != null) {
            return domainName;
        } else {
            if (domainNamePattern != null) {
                Matcher matcher = domainNamePattern.matcher(request.getServerName());
                if (matcher.matches()) {
                    return matcher.group(1);
                }
            }

            return null;
        }
    }

    private static String getCookiePath(HttpServletRequest request) {
        return cookiePath == null ? request.getContextPath() + "/" : cookiePath;
    }

    static {
        char c;
        for (c = '0'; c <= '9'; ++c) {
            domainValid.set(c);
        }

        for (c = 'a'; c <= 'z'; ++c) {
            domainValid.set(c);
        }

        for (c = 'A'; c <= 'Z'; ++c) {
            domainValid.set(c);
        }

        domainValid.set(46);
        domainValid.set(45);
    }
}
